package com.aplikata.evok.service;

import java.util.ArrayList;
import java.util.List;

import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
import org.springframework.stereotype.Service;

import com.aplikata.bo.Role;
import com.aplikata.constants.ConstantsMsg;
import com.aplikata.evok.bo.PatientQtnaire;
import com.aplikata.evok.bo.PatientQtnaireNotice;
import com.aplikata.evok.bo.PatientQtnaireQtInput;
import com.aplikata.evok.bo.PatientQtnaireResult;
import com.aplikata.evok.bo.Qt;
import com.aplikata.evok.bo.QtCategory;
import com.aplikata.evok.bo.Qtnaire;
import com.aplikata.evok.bo.ResultDetail;
import com.aplikata.exception.CustomException;
import com.aplikata.service.PublicServiceImpl;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.YunDateUtil;

/**
 * @ClassName: EvokQtnaireServiceImpl
 * @Description: Manipulation with Qtnaires
 * @author Jasenko
 * @date 16. 5. 2012. 09:40:00
 */
@Service("evokQtnaireService")
public class EvokQtnaireServiceImpl extends PublicServiceImpl implements
		EvokQtnaireService {

	public EvokQtnaireServiceImpl() {
	}

	/*
	 * Title: deleteQtnaire Description:
	 * 
	 * @param qtnaire
	 * 
	 * @throws Exception
	 * 
	 * @see
	 * com.aplikata.evok.service.EvokQtnaireService#deleteQtnaire(com.aplikata
	 * .evok.bo.Qtnaire)
	 */
	public void deleteQtnaire(Qtnaire qtnaire) throws Exception {
		if (FacesUtil.isKeyNull(qtnaire.getId()))
			return;
		qtnaire = (Qtnaire) get(Qtnaire.class, qtnaire.getId());
		if (qtnaire.getParent() != null)
			qtnaire.getParent().getChildren().remove(qtnaire);

		qtnaire.setChildren(null);
		qtnaire.setRoles(null);
		delete(qtnaire);
	}

	/*
	 * Title: deleteQtCategory Description:
	 * 
	 * @param qtCategory
	 * 
	 * @throws Exception
	 * 
	 * @see
	 * com.aplikata.evok.service.EvokQtnaireService#deleteQtCategory(com.aplikata
	 * .evok.bo.QtCategory)
	 */
	@SuppressWarnings("unchecked")
	public void deleteQtCategory(QtCategory qtCategory) throws Exception {
		qtCategory = (QtCategory) get(QtCategory.class, qtCategory.getId());
		if (!qtCategory.getQts().isEmpty()) {
			throw new CustomException((new StringBuilder(
					String.valueOf(qtCategory.getName()))).append(": ")
					.append(FacesUtil.getMessage("qtnaire_category_inuse"))
					.toString());
		}
		getPublicDao().delete(qtCategory);

	}

	/**
	 * @Title: getRootQtnaire
	 * @Description: get questionnaires for one role used in administration part
	 * @param @return
	 * @return TreeNode
	 * @throws
	 */
	@Override
	public TreeNode getRootQtnaire(Role role) {
		return getRootQtnaire(role, true);
	}

	/**
	 * @Title: getRootQtnairePatient
	 * @Description: get questionnaires for one role used in therapy part
	 * @param @return
	 * @return TreeNode
	 * @throws
	 */
	@Override
	public TreeNode getRootQtnairePatient(Role role) {
		return getRootQtnaire(role, false);
	}

	/**
	 * @Title: getRootQtnaire
	 * @Description: TODO
	 * @param @return
	 * @return TreeNode
	 * @throws
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private TreeNode getRootQtnaire(Role role, boolean selection) {
		List<Qtnaire> rootList = null;

		List roleQtnaireList = null;

		if (role == null) {
			rootList = (List<Qtnaire>) findByNamedQuery(
					Qtnaire.QY_FIND_FIRST_LEVEL, new Object[] {});
		} else if (!FacesUtil.isKeyNull(role.getId())) {
			if (selection) {
				rootList = (List<Qtnaire>) findByNamedQuery(
						Qtnaire.QY_FIND_FIRST_LEVEL, new Object[] {});
				roleQtnaireList = findByNamedQuery(Qtnaire.QY_FIND_BY_ROLE,
						new Object[] { role.getId() });
			} else {
				rootList = (List<Qtnaire>) findByNamedQuery(
						Qtnaire.QY_FIND_FIRST_LEVEL_BY_ROLE,
						new Object[] { role.getId() });
			}

		}

		TreeNode rootMenu = new DefaultTreeNode("Root", null);
		if (rootList == null || rootList.isEmpty())
			return rootMenu;

		for (Qtnaire node : rootList) {
			TreeNode tn = new DefaultTreeNode(node, rootMenu);
			tn.setSelected(false);
			if (roleQtnaireList != null && roleQtnaireList.contains(node)) {
				tn.setSelected(true);
			}

			this.addNodes(tn, node, roleQtnaireList);
		}

		return rootMenu;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void addNodes(TreeNode node, Qtnaire qtnairenode,
			List roleQtnaireList) {
		if (qtnairenode == null)
			return;

		String hql = " from Qtnaire q where q.parent.id ="
				+ qtnairenode.getId() + " order by q.sort ";
		List<Qtnaire> children = getPublicDao().find(hql);
		if (children == null || children.isEmpty())
			return;

		for (Qtnaire nd : children) {
			TreeNode tmp = new DefaultTreeNode(nd, node);
			tmp.setSelected(false);
			if (roleQtnaireList != null && roleQtnaireList.contains(nd)) {
				tmp.setSelected(true);
			}

			addNodes(tmp, nd, roleQtnaireList);
		}
	}

	/**
	 * @Title: updateRoleQtnaires
	 * @Description: TODO
	 * @param @param role
	 * @param @param selectedMenus
	 * @param @throws Exception
	 * @return void
	 * @throws
	 */
	public void updateRoleQtnaires(Role role, TreeNode[] selectedQtnaires)
			throws Exception {
		if (role == null || FacesUtil.isKeyNull(role.getId()))
			throw new CustomException("Odaberite Rolu!");

		String sql = " delete  FROM evk_role_qtnaire where role_id = "
				+ role.getId();

		getPublicDao().updateBySql(sql);

		if (selectedQtnaires == null || selectedQtnaires.length == 0)
			return;

		sql = " insert into evk_role_qtnaire values ";

		for (int i = 0; i < selectedQtnaires.length; i++) {
			TreeNode treenode = selectedQtnaires[i];
			Qtnaire qtnaire = (Qtnaire) treenode.getData();
			sql += "(" + role.getId() + "," + qtnaire.getId() + "),";
		}

		if (sql.lastIndexOf(",") >= 0)
			sql = sql.substring(0, sql.trim().length());
		getPublicDao().updateBySql(sql);
	}

	/**
	 * @Title: getPatientQuestionList
	 * @Description: Return the question list for one questionnaire
	 * @param @return
	 * @return List
	 * @throws
	 */
	public List<?> getPatientQuestionList(PatientQtnaire patientQtnaire) {
		if (patientQtnaire == null) {
			return new ArrayList<Object>();
		}
		
		if (!FacesUtil.isKeyNull(patientQtnaire.getId()))
			return getPatientQuestionListExists(patientQtnaire);

		return getPatientQuestionListFresh(patientQtnaire);
	}

	private List<?> getPatientQuestionListExists(PatientQtnaire patientQtnaire) {
		List<Object> resultList = new ArrayList<Object>();
		String sql = "SELECT {epqn.*}, {epqr.*} FROM evk_qt eq"
				+ " join evk_qt_category eqc on eq.qt_category_id = eqc.id"
				+ " left join evk_patient_qtnaire_notice epqn on epqn.qt_id = eq.id"
				+ " left join evk_patient_qtnaire_result epqr on epqr.qt_id = eq.id"
				+ " where epqn.patient_qtnaire_id = " + patientQtnaire.getId()
				+ " or epqr.patient_qtnaire_id = " + patientQtnaire.getId()
				+ " order by eqc.sort, eq.sort";

		List<?> list = getSqlQuery(sql)
				.addEntity("epqn", PatientQtnaireNotice.class)
				.addEntity("epqr", PatientQtnaireResult.class).list();
		if (list == null || list.isEmpty())
			return resultList;

		for (int i = 0; i < list.size(); i++) {
			Object[] obj = (Object[]) list.get(i);
			PatientQtnaireNotice pqn = (PatientQtnaireNotice) obj[0];
			PatientQtnaireResult pqr = (PatientQtnaireResult) obj[1];

			if (pqn != null) {
				resultList.add(pqn);
			} else if (pqr != null) {
				resultList.add(pqr);
			}
		}
		return resultList;
	}

	@SuppressWarnings("unchecked")
	private List<?> getPatientQuestionListFresh(PatientQtnaire patientQtnaire) {
		List<Object> resultList = new ArrayList<Object>();
		List<Qt> qtList = (List<Qt>) findByNamedQuery(Qt.QY_FIND_BY_QTNAIRE,
				new Object[] { patientQtnaire.getQtnaire().getId() });

		for (Qt oneQt : qtList) {
			if (oneQt.getQtCategory().getResult() == null)
				resultList.add(new PatientQtnaireNotice(patientQtnaire, oneQt));
			else
				resultList.add(new PatientQtnaireResult(patientQtnaire, oneQt));
		}
		return resultList;
	}
	
	@SuppressWarnings("unchecked")
	public PatientQtnaire updatePatientQtnaire(PatientQtnaire patientQtnaire,
			List<PatientQtnaireQtInput> resultList) throws Exception {
		
		if (patientQtnaire.getCreateTime() == null)
			throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[]{FacesUtil.getMessage("default_create_time")});
		
		patientQtnaire.setOperTime(YunDateUtil.getDateTime());
		
		patientQtnaire = (PatientQtnaire) this.getPublicDao().merge(patientQtnaire);
		
		for (PatientQtnaireQtInput oneInput : resultList) {
			if(FacesUtil.isKeyNull(oneInput.getId()))
				oneInput.setPatientQtnaire(patientQtnaire);
			if(oneInput instanceof PatientQtnaireResult){
				PatientQtnaireResult oneResult = (PatientQtnaireResult) oneInput;
				if(FacesUtil.isKeyNull(oneResult.getResultId()))
					throw new CustomException(oneInput.getQt().getName()
							+ ": " + FacesUtil.getMessage("patient_qtnaire_answer_required"));
				oneResult.setResultDetail((ResultDetail) get(ResultDetail.class, oneResult.getResultId()));
				merge(oneResult);
			}else if(oneInput instanceof PatientQtnaireNotice){
				PatientQtnaireNotice oneNotice = (PatientQtnaireNotice) oneInput;
				if (oneNotice.getContent() == null || oneNotice.getContent().isEmpty())
					throw new CustomException(oneInput.getQt().getName()
							+ ": " + FacesUtil.getMessage("patient_qtnaire_answer_required"));
				merge(oneNotice);
			}
		}
		return patientQtnaire;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void deletePatientQtnaire(PatientQtnaire patientQtnaire)
			throws Exception {
		getPublicDao().delete(patientQtnaire);	
	}
}
